function DoParameterTypesReplacement(sText)
{
  //replace string with const char*
  var sOutput = sText.replace(/stringresult/g, "const char*");
  sOutput = sOutput.replace(/string/g, "const char*");
  
  //Replace position with long
  sOutput = sOutput.replace(/position/g, "long");

  //Replace bool with BOOL
  sOutput = sOutput.replace(/bool/g, "BOOL");
  
  //Replace textrange with textrange*
  //sOutput = sOutput.replace(/textrange/g, "TextRange*");
  sOutput = sOutput.replace(/textrange/g, "const char*");
  
  //Replace cells with char*
  sOutput = sOutput.replace(/cells/g, "const char*");

  //Replace stringresult with char*
  sOutput = sOutput.replace(/stringresult/g, "const char*");

  //Replace colour with COLORREF
  sOutput = sOutput.replace(/colour/g, "COLORREF");

  //Replace colour with TextToFind*
  //sOutput = sOutput.replace(/findtext/g, "TextToFind*");
  sOutput = sOutput.replace(/findtext/g, "const char*");
  
  //Replace keymod with DWORD
  sOutput = sOutput.replace(/keymod/g, "DWORD");
  
  //Replace formatrange with long
  //sOutput = sOutput.replace(/formatrange/g, "RangeToFormat*");
  sOutput = sOutput.replace(/formatrange/g, "const char*");

  return sOutput;
}

function FindFunctionName(sLine)
{
  //Find the name of the function
  var nFirstSpace = sLine.indexOf(" ");
  var sTemp = sLine.substr(nFirstSpace+1, sLine.length - nFirstSpace);
  nFirstSpace = sTemp.indexOf(" ");
  sTemp = sTemp.substr(nFirstSpace+1, sTemp.length - nFirstSpace);
  var nEquals = sTemp.indexOf("=");
  var sFunction = sTemp.substr(0, nEquals);

  return sFunction;
}

function DeclareParameter(type,name,num)
{
    var p = "\t"+type+" "+name+"=ppParams["+num+"]->";
    switch(type){
      case 'int':
      case 'long':
      case 'BOOL':
      case 'COLORREF':
      case 'DWORD':
        p+="GetNumeric()"; break;
      case 'char*':
      case 'const char*':
        p+="GetString()"; break;
      default: p+="m_String";
    }
    p+=";\r\n";
    return p;
}

function ConvertParameter(type,name,staticType)
{
  if(name=='0') return name;
  switch(type){
    case 'int':
    case 'long':
    case 'BOOL':
    case 'COLORREF':
    case 'DWORD':
      return name;
    case 'char*':
    case 'const char*':
      return "reinterpret_cast<"+staticType+">("+name+")";
    case 'TextRange*':
    case 'TextToFind*':
    case 'RangeToFormat*':
    default: return name;
  }
}

function HandleFunctionBody(sLine)
{
  var notAffectedFunctions=" GetCurLine GetLine GetSelText GetText GetProperty GetPropertyExpanded GetTextRange ";
  var m= /(\w+)\s+(\w+)\s+(\w+)=(\d+)\((\w*)\s?(\w*),\s?(\w*)\s?(\w*)\)/.exec(sLine)
  var fName=m[3];
  if(notAffectedFunctions.indexOf(' '+fName+'')>=0) return '';
  var fType=m[1];
  var retType=m[2];
  var messNum=m[4];
  var param1Type=m[5];
  var param1Name=m[6];
  var param2Type=m[7];
  var param2Name=m[8];
  var numParams = (param1Type==''?0:1)+(param2Type==''?0:1);

  var sBody = "int CSciContext::"+fName+"("+(retType=="void" ? "" : "CValue& retVal, ")+"CValue** ppParams";
  sBody += ")\r\n{\r\n";

  param1Type=DoParameterTypesReplacement(param1Type);
  param2Type=DoParameterTypesReplacement(param2Type);
  param1Name=param1Name==''?'0':param1Name;
  param2Name=param2Name==''?'0':param2Name;
  var nextParam=0;
  if(param1Type!='')
  {
    sBody+=DeclareParameter(param1Type,param1Name,nextParam);
    nextParam++;
  }
  if(param2Type!='')
  {
    sBody+=DeclareParameter(param2Type,param2Name,nextParam);
  }
  
  if(retType=='void')
  {
    sBody += "\tm_pSciCtrl->Call(SCI_"+(fName.toUpperCase())+", ";
  }else{
    sBody += "\tretVal.SetType(CType(1));\r\n";
    sBody += "\tretVal.m_Number=m_pSciCtrl->Call(SCI_"+(fName.toUpperCase())+", ";
  }
    sBody += ConvertParameter(param1Type,param1Name,'WPARAM')+", ";
    sBody += ConvertParameter(param2Type,param2Name,'LPARAM')+");\r\n";
    sBody += "\treturn TRUE;\r\n}\r\n";

  return sBody;
}

function HandleFunctionHeader(sLine)
{
  var notAffectedFunctions=" GetCurLine GetLine GetSelText GetText GetProperty GetPropertyExpanded GetTextRange ";
  var m= /(\w+)\s+(\w+)\s+(\w+)=(\d+)\((\w*)\s?(\w*),\s?(\w*)\s?(\w*)\)/.exec(sLine)
  var fName=m[3];
  if(notAffectedFunctions.indexOf(' '+fName+'')>=0) return '';
  var fType=m[1];
  var retType=m[2];
  var messNum=m[4];
  var param1Type=m[5];
  var param1Name=m[6];
  var param2Type=m[7];
  var param2Name=m[8];
  var numParams = (param1Type==''?0:1)+(param2Type==''?0:1);

  var sBody = "\t"+(retType=="void" ? "BL_PROC(" : "BL_FUNC(");
  sBody += fName+", \""+fName+"\", "+numParams+");";
  return sBody;
}


//The actual script implementation

fileName=''
//Ensure the number of arguments are correct
if (WScript.Arguments.length < 1)
{
  //WScript.Echo("Usage: ConvertScintillaiface PathToScintillaiface [/CPP]");
  //WScript.Quit(1);
  fileName="Scintilla.iface"
}else{
  fileName=WScript.Arguments(0)
}

//Create the file system object
var g_FSO = new ActiveXObject("Scripting.FileSystemObject");

//Open the file as text for parsing
var ifaceFile = g_FSO.OpenTextFile(fileName, 1, false);
var cppOutFile = g_FSO.OpenTextFile("wrapper.inl", 2, true);
var hOutFile = g_FSO.OpenTextFile("wrapper.h", 2, true);

var bCreateHeader = true;

//Read in all the text from the file
var bHandlingDeprecatedCategory = false;
var sLine;
while(!ifaceFile.AtEndOfStream)
{
  sLine = ifaceFile.ReadLine();
  if (sLine.length)
  {
    if (sLine.charAt(0) != "#")
    {
      if (sLine.indexOf("fun") == 0)
      {
        if (!bHandlingDeprecatedCategory)
        {
          cppOutFile.WriteLine(HandleFunctionBody(sLine));
          hOutFile.WriteLine(HandleFunctionHeader(sLine));
        }
      }
      else if (sLine.indexOf("get") == 0)
      {
        var sFunctionName = FindFunctionName(sLine);        

        if (!bHandlingDeprecatedCategory && sFunctionName != "GetDirectFunction" && sFunctionName != "GetDirectPointer")
        {
          cppOutFile.WriteLine(HandleFunctionBody(sLine));
          hOutFile.WriteLine(HandleFunctionHeader(sLine));
        }
      }
      else if (sLine.indexOf("set") == 0)
      {
        if (!bHandlingDeprecatedCategory)
        {
          cppOutFile.WriteLine(HandleFunctionBody(sLine));
          hOutFile.WriteLine(HandleFunctionHeader(sLine));
        }
      }
      else if (sLine.indexOf("cat") == 0)
      {
        if (sLine.indexOf("Deprecated") != -1)
          bHandlingDeprecatedCategory = true;
        else
          bHandlingDeprecatedCategory = false;
      }
    }
  }
}
cppOutFile.Close()
hOutFile.Close()

